PIC16F877 is one of the advanced and commonly used Peripheral Interface Microcontroller from Microchip. Simplicity, quality, ease of availability and low price makes them ideal for different applications. Also, this PIC features all components that modern microcontrollers have.
Some of the remarkable features of this PIC microcontroller are listed below.
PIC16F877 has 5 basic I/O ports. These are denoted by PORT A, PORT B, PORT C, PORT D, and PORT E. These ports are used for input/ output interfacing.
Features of Input/Output Ports.
Note: If we want to set PORT A as an input, just set TRIS(A) bit to logical ‘1’ and want to set PORT B as an output, just set the PORT B bits to logical ‘0’.
Program1: // the port testing program which toggles all the port pins #include <pic.h> #include"delay.h"// THE DELAY FUNCTION IS ATTACHED //This subfunction configures the ports of pic as output void TRISCONFIG () { TRISA = 0; //configuring portA TRISB = 0; //configuring portB TRISC = 0; //configuring portC TRISD = 0; //configuring portD TRISE = 0; //configuring portE // INTIALISING ALL THE PORTS WITH ZEROS PORTA=0; PORTB=0; PORTC=0; PORTD=0; PORTE=0; } void main () { TRISCONFIG (); // CALLING OF PORT CONFIG FUNCTION while (1)//looping continuously { PORTA=~PORTA; // toggling the port values so as to make it blink PORTB=~PORTB; PORTC=~PORTC; PORTD=~PORTD; PORTE=~PORTE; DelayMs (500);// CALLING A DELAY OF 500 MS TWICE : REFER DELAY.C DelayMs (500); } } Program2: 2ND PORT // THE PORT program for interfacing switches and led // connect the switches in pull up state to portb // connect the leds to portd // whenever a switch in the portb is kept pressed the ledsin portd toggles #include <pic.h> #include"delay.h"// THE DELAY FUNCTION IS ATTACHED //This subfunction configures the ports of pic as output and input void TRISCONFIG() { TRISB = 0xFF; //configuring portB as input TRISD = 0; //configuring portD as output // INTIALISING ALL THE PORTD WITH ZEROS PORTD=0; PORTE=~PORTE; DelayMs(500);// CALLING A DELAY OF 500 MS TWICE : REFER DELAY.C DelayMs(500); } void main() { TRISCONFIG(); // CALLING OF PORT CONFIG FUNCTION while(1)//looping continously { if(PORTB!=0XFF) //check for key press in portb { PORTE=~PORTE; DelayMs(500);// CALLING A DELAY OF 500 MS TWICE : REFER DELAY.C DelayMs(500); } } }
The Universal Synchronous Asynchronous Receiver Transmitter (USART) present in PIC16F877 is one among the two serial I/O modules. It can be used as a full-duplex asynchronous system which can communicate with the peripheral devices. The peripheral devices can be a CRT terminal, personal computer. Also the UART of PIC16F877 can be used as a half-duplex synchronous system. This half duplex system can communicate with peripheral devices like A/D or D/A integrated circuits, serial EEPROMs etc.
The USART can be configured in the following modes:
Bit SPEN (RCSTA<7>) and TRISC<7:6> is to be set to configure RC6/TX/CK and RC7/RX/DT as USART. USART in PIC16F877A has multi-processor communication capability using 9-bit address detection.
When setting up an UART Transmission, follow these steps:
1. Initialize SPBRG for baud rate. Inorder to set a high-speed baud rate, set BRGH.
2. Enable asynchronous serial port by clearing SYNC and set SPEN.
3. If interrupts are desired, then set TXIE.
4. For 9-bit transmission set TX9.
5. Enable transmission by setting TXEN and TXIF.
6. If 9-bit transmission is used; ninth bit must be loaded in TX9D.
7. Load data to the TXREG register.
8. If interrupts are used, make GIE and PEIE of INTCON register to set mode.
//transmits a string
#include <pic.h>
#include "delay.h" // including the delay header
#define BAUD 9600 // defining the required baud rate
#define FOSC 4000000L // define the xtal frequency provided
#define DIVIDER ((int)(FOSC/(16UL * BAUD) -1)) // equation for calculating the divider value to store in baud rate register
//refer the uart tutorial
// function to transmit a single byte through uart
void putchs(unsigned char byte)
{
TXREG = byte; /* output one byte */
while(!TRMT) /* set when register is empty */
continue;
}
// this function transmits a string through uart
void prints(const char *uptr)
{
while(*uptr != '\0')
{
putchs(*uptr);
uptr++;
DelayMs(1);
}
}
// uart intialising refer the uart tutorial for register details
void uart_Init()
{
RCSTA = 0;
TXSTA = 0;
RCREG = 0;
BRGH = 1; //set high baud rate
SYNC = 0; //select async communication
SPBRG = DIVIDER;// calculated from above equation, if BRGH=1;
SPEN = 1; // serial port enable
TXEN = 1; // transmission enable
GIE = 0; // disabling the interrupts
RCIF = 0;
PEIE = 0;
RCIE = 1; //enabling the reception notification flag
CREN = 1; // enabling continous reception
}
void main()
{
uart_Init(); // intialising uart
prints("hello world");// trasmitting string
while(1);// stopping from overrun
}
When setting up an UART Reception, follow these steps:
1. Initialize SPBRG for baud rate. Inorder to set a high-speed baud rate set BRGH.
2. Enable the asynchronous serial port by clearing SYNC and set SPEN.
3. If interrupts are desired, then set RCIE.
4. If 9-bit reception is used, set RX9.
5. Enable reception by setting CREN.
6. Flag bit RCIF will be set when reception is complete and an interrupt will be generated if enable bit RCIE is set.
7. Read the RCSTA register.
8. Read RCREG register.
9. Clear error by CREN.
10. If using interrupts, ensure that GIE and PEIE (bits 7 and 6) of the INTCON register are set.
//transmits a a recieved byte
#include <pic.h>
#include "delay.h" // including the delay header
#define BAUD 9600 // defining the required baud rate
#define FOSC 4000000L // define the xtal frequency provided
#define DIVIDER ((int)(FOSC/(16UL * BAUD) -1)) // equation for calculating the divider value to store in baud rate register
void putchs(unsigned char byte)
{
TXREG = byte; /* output one byte */
while(!TRMT) /* set when register is empty */
continue;
}
// this function transmits a string through uart
void prints(const char *uptr)
{
while(*uptr != '\0')
{
putchs(*uptr);
uptr++;
DelayMs(1);
}
}
// uart intialising refer the uart tutorial for register details
void uart_Init()
{
RCSTA = 0;
TXSTA = 0;
RCREG = 0;
BRGH = 1; //set high baud rate
SYNC = 0; //select async communication
SPBRG = DIVIDER;// calculated from above equation, if BRGH=1;
SPEN = 1; // serial port enable
TXEN = 1; // transmission enable
GIE = 0; // disabling the interrupts
RCIF = 0;
PEIE = 0;
RCIE = 1; //enabling the reception notification flag
CREN = 1; // enabling continous reception
}
void main()
{
uart_Init(); // intialising uart
while(1)// looping for ever
{
while(RCIF==0);// waiting for reception
{
RCIF=0; // CLEARING THE BIT
putchs(RCREG);// trasmitting byte
}
}
}
Analog-to-Digital Converter for 28-pin devices has five inputs and for 40/44-pin devices has eight inputs. In PIC16F877, conversion of analog signal results in 10-bit digital number. A/D module has low and high voltage reference input. It is software selectable for VSS, VDD, RA2, RA3. The A/D converter device can operate in Sleep mode. During Sleep, clock of the converter must be derived from the RC oscillator.
The A/D in PIC16F877A has four registers. These registers are:
• A/D Control Register 0 (ADCON0)
• A/D Result High Register (ADRESH)
• A/D Result Low Register (ADRESL)
• A/D Control Register 1 (ADCON1)
To do an A/D Conversion, follow these steps:
1. Configure A/D module
• Configure analog pins and digital I/O (ADCON1)
• Select A/D input channel (ADCON0)
• Select A/D conversion clock (ADCON0)
• Turn ON A/D module (ADCON0)
2. Configure A/D interrupt (if desired)
• Clear ADIF
• Set ADIE
• Set PEIE
• Set GIE
3. Wait for acquisition time.
4. Start conversion
• Set GO/DONE bit (ADCON0)
5. Wait for A/D conversion to complete by either:
• Polling GO/DONE bit to be cleared or,
• Wait for A/D interrupt.
6. Read A/D Result register, clear ADIF.
7. For next conversion, go to step 1 or step 2 as required. A/D conversion time per bit is defined as TAD.
#include <pic.h>
#include"delay.h"
int adcval; // defining adc integer
void ADC_Init()
{
TRISA = 0XEF;//configuring adc ports as input
TRISE = 0X07;
ADCON1 = 0X80;// configuring all ports as analog ports
}
// fucntion for reading the adc value
int read_adc(char channel)
{
int val;
ADCON1 = 0x80; //port config
ADCON0 = 0x81 | channel << 3;// channel selection SET THE CHANNEL NUMBER
DelayUs(50);
ADGO = 1;//turn on the adc
while(ADGO) // checking the adc conversion
continue;
val = ADRESH;
val = val<<8 | ADRESL;// combining the both adresh and adresl values to a single variable
return (val);
}
void main()
{
TRISD=0X00;
PORTD=0X00;
ADC_Init();// adcintialising
while(1)// loop for ever
{
adcval=read_adc(0);
if(adcval> 500) //checking the adc value
{
PORTD=0XFF; //setting the port value as high if adc value greater than 500
}
else // reseting the port value
{
PORTD=0X00;
}
}
}
A PWM output has a time base and a time that the output stays high. Frequency of PWM is inverse of period.
PWM PERIOD
PWM period is specified by PR2 register. PWM period can be calculated using the formula:
PWM Period = [(PR2) + 1] • 4 • TOSC • (TMR2 Prescaler Value)
PWM frequency is defined by 1/ [PWM period].
When TMR2 is equal to PR2, first:
• TMR2 is cleared.
• CCP1 pin is set.
• PWM duty cycle is passed from CCPR1L to CCPR1H.
PWM DUTY CYCLE
PWM Duty Cycle = (CCPR1L:CCP1CON<5:4>) • TOSC • (TMR2 Prescaler Value)
The following steps should be taken when configuring the CCP module for PWM operation:
1. Set PWM period by PR2 register.
2. Set PWM duty cycle by writing to CCPR1L register and CCP1CON
3. Make the CCP1 pin an output.
4. Set TMR2 prescaler value and enable Timer2 by writing to T2CON.
5. Configure CCP1 module for PWM operation.
//generating the pwm from pwm1 module
#include <pic.h>
void pwm_Init(){
PR2 = 41;//setting the pwm frequency
CCP1CON = 0X0C;//configuring the pwm
CCPR1L = 0x13; // setting the duty cycle
T2CKPS1 = 0; //setting the prescalar
T2CKPS0 = 0;
TMR2IF = 0;
TMR2IE = 0;
TMR2ON = 1; //timer 2 on
}
void main()
{
pwm_Init();// intialising the pwm
while(1); //stopping the program
}
//configuring the different timers
//subroutines for configuring the different timers
#include <pic.h>
// timer 0 intialising function
void Timer0_Init()
{
T0CS =1;// timer clock source select
T0IF =0; // timer set flag
PSA =0; //prescalar assingment
PS2 =1; // prescale bits
PS1 =1;
PS0 =1;
TMR0 =160;
GIE =1; //interrupts flag set
T0IE =1; // timer interrupt set
PEIE =1;
}
// timer 2 intialising function
void Timer2_Init()
{
PR2 = 95; // period register
TOUTPS0 = 1;
TOUTPS1 = 1; // post scale bit
TOUTPS2 = 1;
TOUTPS3 = 1;
TMR2ON = 0; // timer on bit
TMR2 = 0;
T2CKPS1 = 1; // timer prescale bit
T2CKPS0 = 1;
TMR2IF = 0; //interrupt enable bits
TMR2IE = 1;
PEIE = 1;
}
// timer 1 intialising function
void Timer1_Init()
{
T1CON = 0;
TMR1H = 0x00; // timer register
TMR1L = 0x00;
TMR1ON = 0; // timer on bit
TMR1CS = 0;
T1OSCEN = 0; // timer oscillator bit select
T1CKPS1 = 0;
T1CKPS0 = 0; // prescale bit select
TMR1IE = 0;
TMR1IF = 0; // interrupt bit select
}
// counter 1 intialising function
void counter_Init()
{
T1CON = 0;
TMR1H = 0x00;
TMR1L = 0x00;
TMR1ON = 0;
TMR1CS = 1;
T1SYNC = 1;
T1OSCEN = 0;
TRISC0 = 1;
}